package com.myk.game.gobangchess.rooms.oldrooms;

import com.myk.game.gobangchess.Room;
import com.myk.game.gobangchess.constants.BoardStyleData;
import com.myk.game.gobangchess.constants.ColorCost;
import com.myk.game.gobangchess.constants.WinMode;
import com.myk.game.gobangchess.signs.AroundSign;
import com.myk.game.gobangchess.signs.GroundSign;
import com.myk.game.gobangchess.signs.LineSign;
import com.myk.game.gobangchess.signs.TextSign;
import com.myk.game.gobangchess.utils.GridsUtils;

import java.awt.*;
import java.util.List;
import java.util.*;

/**
 * 对称棋-经典款
 */
public class SymmetricStaticRoom extends Room {

    private static final int maxScore = 9; //对称棋形数量达到此值时开始进行比较  //++当前已经形成的棋块数量不用分数显示，而是在下方有提示文本，颜色从绿色到红色渐变。

    private ActionState actionState; //当前行动状态
    private ChessInfo tempPoint; //切换到移子挤子状态时记录的临时坐标
    private Point fallPoint; //最新落子的坐标
    private LineSign arrowTip; //移动箭头提示信息s
    private List<ChessInfo> pieces; //棋盘上的棋子信息集合
    private List<ChessInfo> pushAblePieces;//可被拉的棋子的集合
    private List<List<ChessInfo>> symmetryPieces; //形成了对称的棋子信息集合

    public SymmetricStaticRoom(String roomName) {
        super(roomName, "\t\t日出设计的对称棋最初版本，现已被新规则替代，而开发者觉得此版本规则相对简洁直观，遂以此方式保留。", "对称棋经典款",BoardStyleData.getGoBangStyle(15,15), true, true);
    }

    @Override
    public String getRuleText() {
        return "【对称棋】规则\n" +
                "1. 棋盘与棋子：\n" +
                "    15x15棋盘，两色棋子，黑先白后，轮流走棋。\n" +
                "2. 落子与拉子：\n" +
                "    每次落一子（称为A子）后，可以选一颗与A子同线(直斜)的对方棋子，使它往A子的方向拉近一格，\n" +
                "    或者选一颗与A子同线(直斜)的己方棋子，使它往A子的方向拉近任意格，\n" +
                "    拉动棋子过程中遇到其他棋子阻碍，可以越过这些棋子。" +
                "    当然也可以选择落子后不拉棋子。\n" +
                "3. 棋块与对称：\n" +
                "    直斜相邻的同色棋子形成一块棋块。\n" +
                "    棋块整体能被一条对称轴(直斜)中分时算对称棋块。\n" +
                "4. 胜负判定：\n" +
                "    走棋后，若走棋方出现不对称棋块，判负。\n" +
                "    走棋后，若走棋方的棋块数量达到九块，棋块数量且大于对方，判负";
    }

    @Override
    public void resetGrids() {
        step = 0;
        blackScore = -1;
        whiteScore = -1;
        gameTip = "-1";
        actionState = null;
        tempPoint = null;
        fallPoint = null;
        arrowTip = null;
        pieces = new ArrayList<>();
        pushAblePieces = new ArrayList<>();
        symmetryPieces = new ArrayList<>();
        curGrids = GridsUtils.copyGrids(originGrids);
        signList.clear();
    }

    @Override
    protected void onStartPrepare() {
        step = 0;
        blackScore = -1;
        whiteScore = -1;
        actionState = ActionState.WAIT_BLACK_FALL;
        gameTip = ActionState.WAIT_BLACK_FALL.tip;
        noticeBlackMove();
    }

    @Override
    public String getGameInfo() {
        curGrids = GridsUtils.copyGrids(originGrids);
        signList.clear();
        //绘制棋子
        if (pieces != null && pieces.size() > 0) {
            for (ChessInfo piece : pieces) {
                curGrids[piece.row][piece.col] = piece.isBlack ? 1 : 2;
            }
        }
        //绘制成型范围标记
        if (symmetryPieces != null && symmetryPieces.size() > 0) {
            for (List<ChessInfo> symmetryPiece : symmetryPieces) {
                List<Integer> signIds = new ArrayList<>();
                for (ChessInfo chessInfo : symmetryPiece) {
                    signIds.add(getIndex(chessInfo.row, chessInfo.col));
                }
                if (symmetryPiece.get(0).isBlack){
                    signList.add(new AroundSign(new ArrayList<>(signIds), ColorCost.BLACK_TRANSLUCENT, ColorCost.TRANSPARENT, 1f));
                }
                else {
                    signList.add(new AroundSign(new ArrayList<>(signIds),  ColorCost.WHITE_TRANSLUCENT, ColorCost.TRANSPARENT, 1f));
                }
            }
        }
        //绘制落子标记
        if (fallPoint != null) {
            signList.add(new GroundSign(getIndex(fallPoint.y, fallPoint.x), ColorCost.TRANSPARENT, ColorCost.NEW_PUT_POINT, 1.0f, 0, 0));
        }
        //绘制拉子提示
        if (arrowTip != null) {
            signList.add(arrowTip);
        }
        //绘制可被拉棋子高亮提示
        if (pushAblePieces != null && pushAblePieces.size() > 0) {
            if (actionState == ActionState.WAIT_BLACK_PULL || actionState == ActionState.WAIT_WHITE_PULL){
                for (ChessInfo pushAblePiece : pushAblePieces) {
                    String pushArrTipStr = getPushArrTipStr(pushAblePiece);
                    signList.add(new TextSign(getIndex(pushAblePiece.row, pushAblePiece.col), pushArrTipStr, ColorCost.NEW_PUT_POINT));
                }
            }
            else if (actionState == ActionState.WAIT_BLACK_PULL_AGAIN || actionState == ActionState.WAIT_WHITE_PULL_AGAIN){
                //绘制确定拉子位置的空格
                if (fallPoint!=null){
                    ChessInfo target = pushAblePieces.get(0);
                    List<Integer> getEmptyIndexes = getEmptyIndexes(target.col,target.row, fallPoint.x, fallPoint.y);
                    for (Integer getEmptyIndex : getEmptyIndexes) {
                        signList.add(new TextSign(getEmptyIndex,"•",ColorCost.NEW_PUT_POINT));
                    }
                }
            }
        }
        return super.getGameInfo();
    }

    //获取可拉棋子和新落棋子之间空格的坐标集合
    private List<Integer> getEmptyIndexes(int col, int row, int pCol, int pRow) {
        List<Integer> emptyIndexes = new ArrayList<>();
        if (col == pCol){
            for (int i = Math.min(row, pRow) + 1; i < Math.max(row, pRow); i++) {
                if (curGrids[i][col] == 0){
                    emptyIndexes.add(getIndex(i, col));
                }
            }
        }
        else if (row == pRow){
            for (int i = Math.min(col, pCol) + 1; i < Math.max(col, pCol); i++) {
                if (curGrids[row][i] == 0){
                    emptyIndexes.add(getIndex(row, i));
                }
            }
        }
        else if (Math.abs(col - pCol) == Math.abs(row - pRow)){
            int minRow = Math.min(row, pRow);
            int maxRow = Math.max(row, pRow);
            int minCol = Math.min(col, pCol);
            int maxCol = Math.max(col, pCol);
            if (col < pCol){
                if (row < pRow){
                    for (int i = minCol + 1; i < maxCol; i++) {
                        if (curGrids[minRow + i - minCol][i] == 0){
                            emptyIndexes.add(getIndex(minRow + i - minCol, i));
                        }
                    }
                }
                else {
                    for (int i = minCol + 1; i < maxCol; i++) {
                        if (curGrids[maxRow - i + minCol][i] == 0){
                            emptyIndexes.add(getIndex(maxRow - i + minCol, i));
                        }
                    }
                }
            }
            else {
                if (row < pRow){
                    for (int i = minCol + 1; i < maxCol; i++) {
                        if (curGrids[maxRow - i + minCol][i] == 0){
                            emptyIndexes.add(getIndex(maxRow - i + minCol, i));
                        }
                    }
                }
                else {
                    for (int i = maxCol - 1; i > minCol; i--) {
                        if (curGrids[maxRow - maxCol + i][i] == 0){
                            emptyIndexes.add(getIndex(maxRow - maxCol + i, i));
                        }
                    }
                }
           }
        }
        return emptyIndexes;
    }

    //根据可拉棋子和新落棋子之间的位置关系，获取拉子箭头提示文本符号
    private String getPushArrTipStr(ChessInfo target) {
        if (fallPoint!=null){
            if (target.row == fallPoint.y && target.col < fallPoint.x) return "→";
            if (target.row == fallPoint.y && target.col > fallPoint.x) return "←";
            if (target.col == fallPoint.x && target.row < fallPoint.y) return "↓";
            if (target.col == fallPoint.x && target.row > fallPoint.y) return "↑";
            if (target.row < fallPoint.y && target.col < fallPoint.x) return "↘";
            if (target.row < fallPoint.y && target.col > fallPoint.x) return "↙";
            if (target.row > fallPoint.y && target.col < fallPoint.x) return "↗";
            if (target.row > fallPoint.y && target.col > fallPoint.x) return "↖";
        }
        return "•";
    }

    @Override
    public void doRule(int row, int col, int value) {
        processFallAction(col, row);
    }

    //处理落子行为
    private void processFallAction(int pCol, int pRow) {
        //根据坐标获取该位置的信息，为null就是空位置，不为空就是已有棋子了
        ChessInfo chessInfo = getChessByPoint(pCol, pRow);
        //等待黑棋落子
        if (checkState(ActionState.WAIT_BLACK_FALL)) {
            //落在空白处
            if (chessInfo == null) {
                fallPiece(true, pCol, pRow); //落下黑棋子
                List<ChessInfo> sameLinePieces = getSameLinePieces(pCol, pRow);//获取与落子处共线的棋子
                if (sameLinePieces.size() > 0){ //有共线棋子时
                    pushAblePieces.addAll(sameLinePieces);
                    changeState(ActionState.WAIT_BLACK_PULL);//切换到等待拉棋状态
                }
                else { //无共线棋子时
                    if (checkFailure(true)){
                        changeState(ActionState.WHITE_WIN);//犯规就白方获胜
                    }
                    else {
                        changeState(ActionState.WAIT_WHITE_FALL); //没失败就让白方继续走
                    }
                }
            }
            else {
                //不可落子
            }
        }
        //等待白棋落子
        else if (checkState(ActionState.WAIT_WHITE_FALL)) {
            //落在空白处
            if (chessInfo == null) {
                fallPiece(false, pCol, pRow); //落下白棋子
                List<ChessInfo> sameLinePieces = getSameLinePieces(pCol, pRow);//获取与落子处共线的棋子
                if (sameLinePieces.size() > 0){ //有共线棋子时
                    pushAblePieces.addAll(sameLinePieces);
                    changeState(ActionState.WAIT_WHITE_PULL);//切换到等待拉棋状态
                }
                else { //无共线棋子时
                    if (checkFailure(false)){
                        changeState(ActionState.BLACK_WIN);//犯规就黑方获胜
                    }
                    else {
                        changeState(ActionState.WAIT_BLACK_FALL); //没失败就让黑方继续走
                    }
                }
            }
            else {
                //不可落子
            }
        }
        //等待黑方拉棋
        else if (checkState(ActionState.WAIT_BLACK_PULL)) {
            //判断是否落子在可拉棋子上
            if (chessInfo!=null && pushAblePieces.contains(chessInfo)) {
                //如果所拉棋子是己方棋子
                if (chessInfo.isBlack){
                    pushAblePieces.clear();
                    pushAblePieces.add(chessInfo);
                    changeState(ActionState.WAIT_BLACK_PULL_AGAIN); //黑方可以再拉一次
                }
                //如果所拉棋子是对方棋子
                else {
                    pullPiece(chessInfo); //执行拉子操作
                    tempPoint = null;
                    pushAblePieces.clear();
                    if (checkFailure(true)){
                        changeState(ActionState.WHITE_WIN);//犯规就白方获胜
                    }
                    else {
                        changeState(ActionState.WAIT_WHITE_FALL); //没失败就让白方继续走
                    }
                }
            }
            //点击了不能拉子的地方就表示放弃拉子
            else {
                tempPoint = null;
                pushAblePieces.clear();
                if (checkFailure(true)){
                    changeState(ActionState.WHITE_WIN);//犯规就白方获胜
                }
                else {
                    changeState(ActionState.WAIT_WHITE_FALL); //没失败就让白方走
                }
            }
        }
        //等待白方拉棋
        else if (checkState(ActionState.WAIT_WHITE_PULL)) {
            //判断是否落子在可拉棋子上
            if (chessInfo!=null && pushAblePieces.contains(chessInfo)) {
                //如果所拉棋子是己方棋子
                if (!chessInfo.isBlack){
                    pushAblePieces.clear();
                    pushAblePieces.add(chessInfo);
                    changeState(ActionState.WAIT_WHITE_PULL_AGAIN); //白方可以再拉一次
                }
                //如果所拉棋子是对方棋子
                else {
                    pullPiece(chessInfo);//执行拉子操作
                    tempPoint = null;
                    pushAblePieces.clear();
                    if (checkFailure(false)){
                        changeState(ActionState.BLACK_WIN);//犯规就黑方获胜
                    }
                    else {
                        changeState(ActionState.WAIT_BLACK_FALL); //没失败就让黑方继续走
                    }
                }
            }
            //点击了不能拉子的地方就表示放弃拉子
            else {
                tempPoint = null;
                pushAblePieces.clear();
                if (checkFailure(false)){
                    changeState(ActionState.BLACK_WIN);//犯规就黑方获胜
                }
                else {
                    changeState(ActionState.WAIT_BLACK_FALL); //没失败就让黑方走
                }
            }
        }
        //等待黑方确定拉子位置
        else if (checkState(ActionState.WAIT_BLACK_PULL_AGAIN)) {
            ChessInfo target = pushAblePieces.get(0); //之前确保了必有一个
            //判断所点击的位置是否在所选的己方可拉棋子和最新落子棋子之间的空格上
            if (isEmptyInBetween(target,fallPoint,pCol,pRow)) {
                pullPieceAgain(target,pCol,pRow); //执行确认拉子位置操作
                tempPoint = null;
                pushAblePieces.clear();
                if (checkFailure(true)){
                    changeState(ActionState.WHITE_WIN);//犯规就白方获胜
                }
                else {
                    changeState(ActionState.WAIT_WHITE_FALL); //没失败就让白方继续走
                }
            }
            //点击了其它位置表示放弃拉子
            else {
                tempPoint = null;
                pushAblePieces.clear();
                if (checkFailure(true)){
                    changeState(ActionState.WHITE_WIN);//犯规就白方获胜
                }
                else {
                    changeState(ActionState.WAIT_WHITE_FALL); //没失败就让白方继续走
                }
            }
        }
        //等待白方确定拉子位置
        else if (checkState(ActionState.WAIT_WHITE_PULL_AGAIN)) {
            ChessInfo target = pushAblePieces.get(0); //之前确保了必有一个
            if (isEmptyInBetween(target,fallPoint, pCol, pRow)) {
                pullPieceAgain(target,pCol,pRow); //执行确认拉子位置操作
                tempPoint = null;
                pushAblePieces.clear();
                if (checkFailure(false)){
                    changeState(ActionState.BLACK_WIN);//犯规就黑方获胜
                }
                else {
                    changeState(ActionState.WAIT_BLACK_FALL); //没失败就让黑方继续走
                }
            }
            //点击了其它位置表示放弃拉子
            else {
                tempPoint = null;
                pushAblePieces.clear();
                if (checkFailure(false)){
                    changeState(ActionState.BLACK_WIN);//犯规就黑方获胜
                }
                else {
                    changeState(ActionState.WAIT_BLACK_FALL); //没失败就让黑方继续走
                }
            }
        }
    }

    //判断所点击的位置是否在所选可拉棋子和新落子棋子中间的空格上
    private boolean isEmptyInBetween(ChessInfo target, Point fallPoint, int col, int row) {
        if (curGrids[row][col] != 0) return false;
        List<Integer> getEmptyIndexes = getEmptyIndexes(target.col,target.row, fallPoint.x, fallPoint.y);
        return getEmptyIndexes.contains(getIndex(row, col));
    }

    //判断是否失败
    private boolean checkFailure(boolean isBlack) {
        symmetryPieces.clear();
        boolean hasUnSymmetryShape = checkSymmetryShape(isBlack);
        checkSymmetryShape(!isBlack);
        if (hasUnSymmetryShape){
            return true;
        }
        if (isBlack){
            return blackScore >= maxScore && blackScore > whiteScore;
        }
        else {
            return whiteScore >= maxScore && whiteScore > blackScore;
        }
    }

    //curGrids中所有棋子中，pCol和pRow在直线和斜线上相同的棋子，并且它们中间存在空格的。 那么这枚棋子可以拉
    private List<ChessInfo> getSameLinePieces(int pCol, int pRow) {
        List<ChessInfo> sameLinePieces = new ArrayList<>();
        for (ChessInfo piece : pieces) {
            if (piece.col == pCol && piece.row == pRow){ //跳过自己
                continue;
            }
            if (piece.col == pCol || piece.row == pRow || Math.abs(piece.col - pCol) == Math.abs(piece.row - pRow) ) {
                if (hasEmptyInBetween(piece.col, piece.row, pCol, pRow)){
                    sameLinePieces.add(piece);
                }
            }
        }
        return sameLinePieces;
    }

    //判断两个点之间是否有空格
    private boolean hasEmptyInBetween(int col, int row, int pCol, int pRow) {
        if (col == pCol){
            for (int i = Math.min(row, pRow) + 1; i < Math.max(row, pRow); i++) {
                if (curGrids[i][col] == 0){
                    return true;
                }
            }
        }
        else if (row == pRow){
            for (int i = Math.min(col, pCol) + 1; i < Math.max(col, pCol); i++) {
                if (curGrids[row][i] == 0){
                    return true;
                }
            }
        }
        else if (Math.abs(col - pCol) == Math.abs(row - pRow)){
            int minRow = Math.min(row, pRow);
            int maxRow = Math.max(row, pRow);
            int minCol = Math.min(col, pCol);
            int maxCol = Math.max(col, pCol);
            if (col < pCol){
                if (row < pRow){
                    for (int i = minCol + 1; i < maxCol; i++) {
                        if (curGrids[minRow + i - minCol][i] == 0){
                            return true;
                        }
                    }
                }
                else {
                    for (int i = minCol + 1; i < maxCol; i++) {
                        if (curGrids[maxRow - i + minCol][i] == 0){
                            return true;
                        }
                    }
                }
            }
            else {
                if (row < pRow){
                    for (int i = minCol + 1; i < maxCol; i++) {
                        if (curGrids[maxRow - i + minCol][i] == 0){
                            return true;
                        }
                    }
                }
                else {
                    for (int i = maxCol - 1; i > minCol; i--) {
                        if (curGrids[maxRow - maxCol + i][i] == 0){
                            return true;
                        }
                    }
                }
           }
        }
        return false;
    }

    //根据坐标点获取棋子
    private ChessInfo getChessByPoint(int pCol, int pRow) {
        for (ChessInfo piece : pieces) {
            if (piece.col == pCol && piece.row == pRow) {
                return piece;
            }
        }
        return null;
    }

    //判断当前状态
    private boolean checkState(ActionState state) {
        return actionState == state;
    }

    //转换状态
    private void changeState(ActionState state) {
        actionState = state;
        gameTip = state.tip;
        refreshUI();
    }

    private void refreshUI() {
        if (checkState(ActionState.WAIT_BLACK_FALL)) {
            stepAdd();
            noticeBlackMove();
        }
        else if (checkState(ActionState.WAIT_WHITE_FALL)) {
            stepAdd();
            noticeWhiteMove();
        }
        else if (checkState(ActionState.BLACK_WIN)) {
            stepAdd();
            doOver(WinMode.BLACK_WIN, player_black.getNickNameOrTemp() + "执黑棋战胜" + player_white.getNickNameOrTemp());
        }
        else if (checkState(ActionState.WHITE_WIN)) {
            stepAdd();
            doOver(WinMode.WHITE_WIN, player_white.getNickNameOrTemp() + "执白棋战胜" + player_black.getNickNameOrTemp());
        }
        else {
            noticeAllRefreshGameInfo();
        }
    }

    //在棋盘上指定坐标上落下新棋子
    private void fallPiece(boolean isBlack, int pCol, int pRow) {
        tempPoint = new ChessInfo(isBlack, pCol, pRow);
        pieces.add(tempPoint); //创建新棋子落下
        setFallTip(pCol, pRow); //添加落子提示
    }

    //将指定坐标上的棋子朝刚落下的那枚棋子移动一次
    private void pullPiece(ChessInfo piece) {
        //根据tempPoint和piece的位置计算移动距离，要求piece向tempPoint靠近一格，如果中间有其它棋子则越过，不能超过tempPoint本身的位置
        int colDiff = 0;
        int rowDiff = 0;

        if (piece.row == tempPoint.row){
            if (piece.col > tempPoint.col){ //向左移动
                for (int i = piece.col; i > tempPoint.col; i--) {
                    ChessInfo chessInfo = getChessByPoint(i - 1, piece.row);
                    if (chessInfo == tempPoint){
                        colDiff = 0;
                        break;
                    }
                    if (chessInfo != null) {
                        colDiff--;
                    }
                    else {
                        colDiff--;
                        break;
                    }
                }
            }
            if (piece.col < tempPoint.col){ //向右移动
                for (int i = piece.col; i < tempPoint.col; i++) {
                    ChessInfo chessInfo = getChessByPoint(i + 1, piece.row);
                    if (chessInfo == tempPoint){
                        colDiff = 0;
                        break;
                    }
                    if (chessInfo != null) {
                        colDiff++;
                    }
                    else {
                        colDiff++;
                        break;
                    }
                }
            }
        }
        if (piece.col == tempPoint.col){
            if (piece.row > tempPoint.row){ //向上移动
                for (int i = piece.row; i > tempPoint.row; i--) {
                    ChessInfo chessInfo = getChessByPoint(piece.col, i - 1);
                    if (chessInfo == tempPoint){
                        rowDiff = 0;
                        break;
                    }
                    if (chessInfo != null) {
                        rowDiff--;
                    }
                    else {
                        rowDiff--;
                        break;
                    }
                }
            }
            if (piece.row < tempPoint.row){ //向下移动
                for (int i = piece.row; i < tempPoint.row; i++) {
                    ChessInfo chessInfo = getChessByPoint(piece.col, i + 1);
                    if (chessInfo == tempPoint){
                        rowDiff = 0;
                        break;
                    }
                    if (chessInfo != null) {
                        rowDiff++;
                    }
                    else {
                        rowDiff++;
                        break;
                    }
                }
            }
        }
        if (piece.row < tempPoint.row && piece.col < tempPoint.col){ //向右下角移动
            for (int i = piece.col; i < tempPoint.col; i++) {
                ChessInfo chessInfo = getChessByPoint(i + 1, piece.row + 1 + rowDiff);
                if (chessInfo == tempPoint){
                    colDiff = 0;
                    rowDiff = 0;
                    break;
                }
                if (chessInfo != null) {
                    colDiff++;
                    rowDiff++;
                }
                else {
                    colDiff++;
                   rowDiff++;
                   break;
                }
            }
        }
        if (piece.row > tempPoint.row && piece.col > tempPoint.col){ //向左上角移动
            for (int i = piece.col; i > tempPoint.col; i--) {
                ChessInfo chessInfo = getChessByPoint(i - 1, piece.row - 1 + rowDiff);
                if (chessInfo == tempPoint){
                    colDiff = 0;
                    rowDiff = 0;
                    break;
                }
                if (chessInfo != null) {
                    colDiff--;
                    rowDiff--;
                }
                else {
                    colDiff--;
                    rowDiff--;
                    break;
                }
            }

        }
        if (piece.row < tempPoint.row && piece.col > tempPoint.col){ //向左下角移动
            for (int i = piece.col; i > tempPoint.col; i--) {
                ChessInfo chessInfo = getChessByPoint(i - 1, piece.row + 1 + rowDiff);
                if (chessInfo == tempPoint){
                    colDiff = 0;
                    rowDiff = 0;
                    break;
                }
                if (chessInfo != null) {
                    colDiff--;
                    rowDiff++;
                }
                else {
                    colDiff--;
                    rowDiff++;
                    break;
                }
            }

        }
        if (piece.row > tempPoint.row && piece.col < tempPoint.col){ //向右上角移动
            for (int i = piece.col; i < tempPoint.col; i++) {
                ChessInfo chessInfo = getChessByPoint(i + 1, piece.row - 1 + rowDiff);
                if (chessInfo == tempPoint){
                    colDiff = 0;
                    rowDiff = 0;
                    break;
                }
                if (chessInfo != null) {
                    colDiff++;
                    rowDiff--;
                }
                else {
                    colDiff++;
                   rowDiff--;
                   break;
                }
            }
        }

        if (colDiff != 0 || rowDiff != 0){ //有移动
            //记录原来坐标
            //设置新的坐标
            piece.col+=colDiff;
            piece.row+=rowDiff;
            //设置箭头提示
            setArrowTip(piece.col-colDiff,piece.row-rowDiff,piece.col,piece.row);
        }
    }

    //确定拉子位置
    private void pullPieceAgain(ChessInfo piece, int pCol, int pRow) {
        setArrowTip(piece.col,piece.row,pCol,pRow);
        piece.row = pRow;
        piece.col = pCol;
    }


    //在指定坐标上添加落子提示
    private void setFallTip(int pCol, int pRow) {
        arrowTip = null; //落新子时清除箭头提示
        fallPoint = new Point(pCol, pRow);
    }

    //指定坐标设定箭头提示
    private void setArrowTip(int fCol, int fRow,int tCol, int tRow) {
        arrowTip = new LineSign(getIndex(fRow, fCol), getIndex(tRow, tCol), ColorCost.MOVE_ARROW, 1);
    }

    //检查所有对称图形添加到集合，返回是否存在不对称的图形
    private boolean checkSymmetryShape(boolean isBlackChess) {
        boolean hasUnSymmetryShape = false;
        List<ChessInfo> iChess = new ArrayList<>(pieces);
        iChess.removeIf(chessInfo -> chessInfo.isBlack != isBlackChess); //保留同色棋子集合
        Map<ChessInfo, Set<ChessInfo>> adjacentGroup = new HashMap<>(); //相邻棋子组成的组
        for (ChessInfo key : iChess) { //每个棋子都建立一个自己的组
            Set<ChessInfo> set = new HashSet<>();
            set.add(key);
            adjacentGroup.put(key, set);
        }
        int size = iChess.size();
        for (int i = 0; i < size; i++) { //第一次遍历所有相邻棋子建立相邻关系
            for (int j = i + 1; j < size; j++) { //保证任意两个棋子只判断一次
                ChessInfo a = iChess.get(i);
                ChessInfo b = iChess.get(j);
                if (isAdjacent(a, b)) {
                    adjacentGroup.get(a).add(b);
                    adjacentGroup.get(b).add(a);
                }
            }
        }
        //printAdjacentGroup("第一次建立关系", adjacentGroup);
        Map<ChessInfo, Set<ChessInfo>> blockGroup = new HashMap<>();
        for (int i = 0; i < size; i++) { //第二次遍历所有邻组合并
            ChessInfo a = iChess.get(i);//因为adjacentGroup是map没有顺序索引所以借助iChess集合来遍历
            Set<ChessInfo> aSet = adjacentGroup.get(a);
            for (ChessInfo blockKey : blockGroup.keySet()) {  //判断这一组是否和已经有的块有交集，保证块不重复
                Set<ChessInfo> blockSet = blockGroup.get(blockKey);
                if (isIntersection(aSet, blockSet)) { //如果有的话
                    a = blockKey;   //就还是用最早的键来判断
                    blockSet.addAll(aSet); //且把这一组的所有棋子添加到块中
                    aSet = blockSet; //且用最全的集合来判断
                }
            }
            for (int j = i + 1; j < size; j++) {
                ChessInfo b = iChess.get(j);
                Set<ChessInfo> bSet = adjacentGroup.get(b);
                if (isIntersection(aSet, bSet)) {
                    aSet.addAll(bSet); //判断过有交集的都要收集起来以免后面的漏判
                    blockGroup.put(a, aSet); //这里的a始终是最早的块键
                }
            }
        }
        //blockGroup添加所有adjacentGroup中value（Set<ChessInfo>）长度为1的块
        for (ChessInfo key : adjacentGroup.keySet()) {
            Set<ChessInfo> set = adjacentGroup.get(key);
            if (set.size() == 1) {
                blockGroup.put(key, set);
            }
        }
        //printAdjacentGroup("合并邻组后", blockGroup);
        Map<ChessInfo, Set<ChessInfo>> singleGroup = new HashMap<>();//此时可能出现来自不同相邻关系组成的相同集合的组，将其净化掉
        for (ChessInfo blockKey : blockGroup.keySet()) {
            Set<ChessInfo> blockSet = blockGroup.get(blockKey);
            boolean isSetEqual = false;
            for (ChessInfo singleKey : singleGroup.keySet()) {
                Set<ChessInfo> singleSet = singleGroup.get(singleKey);
                isSetEqual = isSetEqual(blockSet, singleSet);
                if (isSetEqual) {  //一旦存在相同就不要继续比较了，这组不加到singleGroup中
                    break;
                }
            }
            if (!isSetEqual) {
                singleGroup.put(blockKey, blockSet);
            }
        }
        //printAdjacentGroup("去除相同组后", singleGroup);
        if (isBlackChess) blackScore = singleGroup.size();
        else whiteScore = singleGroup.size();
        for (ChessInfo key : singleGroup.keySet()) {
            Set<ChessInfo> singleSet = singleGroup.get(key);
            if (singleSet.size() == 1){
                symmetryPieces.add(new ArrayList<>(singleSet)); //数量为1时不用计算就是对称棋形
                continue;
            }
            int minCol = -1, minRow = -1, maxCol = -1, maxRow = -1;
            for (ChessInfo chessInfo : singleSet) { //获取区间范围
                if (minCol == -1) { //注意第一次赋予初值
                    minCol = chessInfo.col;
                    maxCol = chessInfo.col;
                    minRow = chessInfo.row;
                    maxRow = chessInfo.row;
                }
                if (chessInfo.col > maxCol) {
                    maxCol = chessInfo.col;
                }
                if (chessInfo.col < minCol) {
                    minCol = chessInfo.col;
                }
                if (chessInfo.row > maxRow) {
                    maxRow = chessInfo.row;
                }
                if (chessInfo.row < minRow) {
                    minRow = chessInfo.row;
                }
            }
            float midCol = (minCol + maxCol) / 2f; //获取中心点横坐标，用于后续计算
            float midRow = (minRow + maxRow) / 2f; //获取中心点纵坐标，用于后续计算
            if (checkHorizontalSymmetry(singleSet, midCol)) {
                symmetryPieces.add(new ArrayList<>(singleSet));
            }
            else if (checkVerticalSymmetry(singleSet, midRow)) {
                symmetryPieces.add(new ArrayList<>(singleSet));
            }
            else if (checkPositiveSymmetry(singleSet, midCol, midRow)) {
                symmetryPieces.add(new ArrayList<>(singleSet));
            }
            else if (checkNegativeSymmetry(singleSet, midCol, midRow)) {
                symmetryPieces.add(new ArrayList<>(singleSet));
            }
            else {
                hasUnSymmetryShape = true;
            }
        }
        return hasUnSymmetryShape;
    }

    //判断是否水平对称无斜率（一条竖线两边全等）
    private boolean checkHorizontalSymmetry(Set<ChessInfo> blockChessSet, float midCol) {
        Set<Point> blockSet = new HashSet<>();
        for (ChessInfo chessInfo : blockChessSet) {
            blockSet.add(new Point(chessInfo.col, chessInfo.row));
        }
        Set<Point> left = new HashSet<>();
        Set<Point> right = new HashSet<>();
        for (Point chessInfo : blockSet) {
            if (chessInfo.x < midCol) {
                left.add(chessInfo);
                float diff = midCol - chessInfo.x; //计算要翻转的值
                chessInfo.x = (int) (midCol + diff); //翻转坐标
            }
            else if (chessInfo.x > midCol) {
                right.add(chessInfo);
            }
        }
        boolean isFlag = isSameCoordinate(left, right); //判断两组棋子横纵坐标是否全等
        return isFlag;
    }

    //判断是否垂直对称（一条横线两边全等）
    private boolean checkVerticalSymmetry(Set<ChessInfo> blockChessSet, float midRow) {
        Set<Point> blockSet = new HashSet<>();
        for (ChessInfo chessInfo : blockChessSet) {
            blockSet.add(new Point(chessInfo.col, chessInfo.row));
        }
        Set<Point> top = new HashSet<>();
        Set<Point> bottom = new HashSet<>();
        for (Point chessInfo : blockSet) {
            if (chessInfo.y < midRow) {
                top.add(chessInfo);
                float diff = midRow - chessInfo.y; //计算要翻转的值
                chessInfo.y = (int) (midRow + diff); //翻转坐标
            }
            else if (chessInfo.y > midRow) {
                bottom.add(chessInfo);
            }
        }
        boolean isFlag = isSameCoordinate(top, bottom);
        return isFlag;
    }

    //判断是否以45°的斜线对称
    private boolean checkPositiveSymmetry(Set<ChessInfo> blockChessSet, float midCol, float midRow) {
        Set<Point> blockSet = new HashSet<>();
        for (ChessInfo chessInfo : blockChessSet) {
            blockSet.add(new Point(chessInfo.col, chessInfo.row));
        }
        Set<Point> leftTop = new HashSet<>();
        Set<Point> rightBottom = new HashSet<>();
        float split = midCol + midRow;
        for (Point chessInfo : blockSet) {
            if (chessInfo.y + chessInfo.x < split) {
                leftTop.add(chessInfo);
                //先求两条直线的交点
                float b = midCol + midRow; //根据公式y = ax + b;a=-1; 求对称线的公式需要的参数
                float h = chessInfo.y - chessInfo.x; //求对齐线的公式需要的参数
                float jX = (b - h) / 2; //求出垂线交点x
                float jY = (b + h) / 2;//求出垂线交点y
                float diffX = jX - chessInfo.x;
                chessInfo.x = (int) (jX + diffX);
                float diffY = jY - chessInfo.y;
                chessInfo.y = (int) (jY + diffY);
            }
            else if (chessInfo.y + chessInfo.x > split) {
                rightBottom.add(chessInfo);
            }
        }
        boolean isFlag = isSameCoordinate(leftTop, rightBottom);
        return isFlag;
    }

    //判断是否以-45°的斜线对称
    private boolean checkNegativeSymmetry(Set<ChessInfo> blockChessSet, float midCol, float midRow) {
        Set<Point> blockSet = new HashSet<>();
        for (ChessInfo chessInfo : blockChessSet) {
            blockSet.add(new Point(chessInfo.col, chessInfo.row));
        }
        Set<Point> left = new HashSet<>();
        Set<Point> right = new HashSet<>();
        for (Point chessInfo : blockSet) {  //先全部水平翻转，这样midCol和midRow不会变，而变成可以以正45°斜线对称了
            if (chessInfo.x < midCol) {
                left.add(chessInfo);
                float diff = midCol - chessInfo.x;
                chessInfo.x = (int) (midCol + diff);
            }
            else if (chessInfo.x > midCol) {
                right.add(chessInfo);
                float diff = chessInfo.x - midCol;
                chessInfo.x = (int) (midCol - diff); //还原改变
            }
        }
        Set<Point> leftTop = new HashSet<>();
        Set<Point> rightBottom = new HashSet<>();
        float split = midCol + midRow;
        for (Point chessInfo : blockSet) {
            if (chessInfo.y + chessInfo.x < split) {
                leftTop.add(chessInfo);
                float b = midCol + midRow; //根据公式y = ax + b;a=-1; 求对称线的公式需要的参数
                float h = chessInfo.y - chessInfo.x; //求对齐线的公式需要的参数
                float jX = (b - h) / 2; //求出垂线交点x
                float jY = (b + h) / 2;//求出垂线交点y
                float diffX = jX - chessInfo.x;
                chessInfo.x = (int) (jX + diffX);
                float diffY = jY - chessInfo.y;
                chessInfo.y = (int) (jY + diffY);
            }
            else if (chessInfo.y + chessInfo.x > split) {
                rightBottom.add(chessInfo);
            }
        }
        boolean isFlag = isSameCoordinate(leftTop, rightBottom);
        return isFlag;
    }

    //打印邻组，邻组是我算法里的一个中间概念
    private void printAdjacentGroup(String title, Map<?, Set<ChessInfo>> adjacentGroup) {
        int row = curGrids.length;
        System.out.println(title + "有" + adjacentGroup.size() + "组");
        for (Object key : adjacentGroup.keySet()) {
            ChessInfo keyChess = (ChessInfo) key;
            String colStr = String.valueOf((char) ('A' + keyChess.col));
            String rowStr = String.valueOf(keyChess.row + 1);
            System.out.print(colStr + rowStr + "组 ");
            for (ChessInfo chessInfo : adjacentGroup.get(key)) {
                String colStr2 = String.valueOf((char) ('A' + chessInfo.col));
                String rowStr2 = String.valueOf(chessInfo.row + 1);
                System.out.print(colStr2 + rowStr2 + "；");
            }
            System.out.println("。");
        }
    }

    //判断两个棋子是否相邻(直向和斜向相邻都算,位置相同不算)
    private boolean isAdjacent(ChessInfo a, ChessInfo b) {
        if (a.col == b.col && a.row == b.row) {
            return false;
        }
        else {
            return Math.abs(a.col - b.col) <= 1 && Math.abs(a.row - b.row) <= 1;
        }
    }

    //判断两组棋子横纵坐标是否全等
    private boolean isSameCoordinate(Set<Point> aSet, Set<Point> bSet) {
        if (aSet.size() != bSet.size()) {
            return false;
        }
        else {
            for (Point chessInfo : aSet) {
                boolean same = false;
                for (Point info : bSet) {
                    if (info.y == chessInfo.y && info.x == chessInfo.x) {
                        same = true;
                        break;
                    }
                }
                if (!same) {
                    return false;
                }
            }
        }
        return true;
    }

    //判断两个邻组是否有交集（只要有一个棋子双方都存在就算有交集）
    private boolean isIntersection(Set<ChessInfo> aSet, Set<ChessInfo> bSet) {
        Set<ChessInfo> resSet = new HashSet<>(aSet);
        resSet.retainAll(bSet); //++这个可能无法判断出来顺序不一致的情况
        return resSet.size() > 0;
    }

    //判断两个集合是否相同
    public boolean isSetEqual(Set<ChessInfo> aSet, Set<ChessInfo> bSet) {
        int a = aSet.size();
        int b = bSet.size();
        if (a == b) {
            Set<ChessInfo> resSet = new HashSet<>();
            resSet.addAll(aSet);
            resSet.addAll(bSet);
            int c = resSet.size();
            return c == a;
        }
        else {
            return false;
        }
    }

    private static class ChessInfo {

        public boolean isBlack;
        public int col;
        public int row;

        public ChessInfo(boolean isBlack, int col, int row) {
            this.isBlack = isBlack;
            this.col = col;
            this.row = row;
        }
    }

    private enum ActionState {
        /**
         * 等待黑棋落子
         */
        WAIT_BLACK_FALL("等待黑方落子..."),
        /**
         * 等待白棋落子
         */
        WAIT_WHITE_FALL("等待白方落子..."),
        /**
         * 等待黑方拉子
         */
        WAIT_BLACK_PULL("等待黑方拉子..."),
        /**
         * 等待白方拉子
         */
        WAIT_WHITE_PULL("等待白方拉子..."),
        /**
         * 等待黑方确定拉子位置
         */
        WAIT_BLACK_PULL_AGAIN("等待黑方确定拉子位置..."),
        /**
         * 等待白方确定拉子位置
         */
        WAIT_WHITE_PULL_AGAIN("等待白方确定拉子位置..."),
        /**
         * 对弈结束，黑方获胜，棋盘不再接受事件
         */
        BLACK_WIN("恭喜黑棋获胜！"),
        /**
         * 对弈结束，白方获胜，棋盘不再接受事件
         */
        WHITE_WIN("恭喜白棋获胜！");

        /**
         * 该状态对应的操作提示
         */
        public final String tip;

        ActionState(String tip) {
            this.tip = tip;
        }
    }

}
